package fg.objects;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Vector2f;

import fg.Resources;
import fg.animation.AnimationSequence;
import fg.animation.easing.ValueEasingAnimation;
import fg.math.Easing;
import fg.sprite.Sprite;

/**
 * TODO: Pull Back
 * TODO: Wave-Effect
 * TODO: Fish
 * TODO: Player
 * @author robin
 *
 */
public class Rod extends Sprite {

	private static final float PEAK_ANGLE = -75f;

	private enum RodState {
		Default, CastBack, CastForward, ReelIn, Hold
	}

	private RodState state;
	private AnimationSequence animationSequence;
	protected Sprite owner;
	protected FishingLine fishingLine;
	protected Lure lure;
	protected boolean lureAttached = true;
	protected float attachedX = 192f;
	protected float attachedY = 10f;

	public Rod() {
		super(Resources.rod);
		state = RodState.Default;
		lure = new Lure(this, Resources.lureSmall);
		fishingLine = new FishingLine(this, lure);
		animationSequence = new AnimationSequence();
	}

	public void update(int delta) {
		if (state == RodState.Default) {

		} else if (state == RodState.CastBack) {
			animationSequence.update(delta);
			if (!animationSequence.isActive()) {
				switchState(RodState.CastForward);
			}
		} else if (state == RodState.CastForward) {
			animationSequence.update(delta);
			if (!animationSequence.isActive()) {
				switchState(RodState.Hold);
			}
		}

		lure.update(delta);
	}

	public void render(Graphics g) {
		float rx = x + pivotX;
		float ry = y + pivotY;
		
		g.rotate(rx, ry, angle);
		image.draw(x, y);

		if (lureAttached) {
			lure.renderCentered(g, x + attachedX, y + attachedY);
		}
		g.rotate(rx, ry, -angle);

		if (!lureAttached) {
			lure.renderCentered(g);
		}

		g.drawString("Angle: " + Math.round(angle), 10f, 70f);
		g.drawString("Rod: " + Math.round(lure.getY()), 10f, 90f);
	}
	
	/**
	 * @param position location of current object
	 * @param rotationPoint to rotate around
	 * @param rad angle in radians
	 * @return new position
	 */
	private Vector2f rotateAroundPoint(Vector2f position, Vector2f rotationPoint, double rad) {
		Vector2f displacement = new Vector2f(position).sub(rotationPoint);
		Vector2f newPos = new Vector2f();
		newPos.x = (float) (displacement.x * Math.cos(rad) + displacement.y * Math.sin(rad));
		newPos.y = (float) (displacement.y * Math.cos(rad) - displacement.x * Math.sin(rad));
		newPos.add(rotationPoint);
		return newPos;
	}

	public void action() {
		if (canStartCasting()) {
			switchState(RodState.CastBack);
		} else if (canPushLure()) {
			pushLure();
		}
	}
	
	private void pushLure() {
		lureAttached = false;
		System.out.println("Push Lure!");
		System.out.println("Range score: " + getRangeScore());
		
		Vector2f location = new Vector2f(x + pivotX, y + pivotY);
		Vector2f point = new Vector2f(x + attachedX, y + attachedY);
		point = rotateAroundPoint(point, location, Math.toRadians(Math.abs(angle)));
		
		double rad = Math.toRadians(angle); 
		float vx = -(float) Math.sin(rad);
		float vy = (float) Math.cos(rad);
		
		float perCent = getRangeScore() * 0.1f;
		
		lure.setPosition(point.x, point.y);
		lure.setVelocity(vx * perCent, vy * perCent);
		System.out.println(perCent);
	}

	/**
	 * Calculates the Range score. Best push moment is a score of 100.
	 * 
	 * @return range score
	 */
	private float getRangeScore() {
		return (100f - Math.abs(PEAK_ANGLE - angle));
	}

	private boolean canStartCasting() {
		return ((RodState.Hold == state && lureAttached) || RodState.Default == state);
	}

	private boolean canPushLure() {
		return (RodState.CastForward == state);
	}
	
	private boolean canReelIn() {
		return (RodState.ReelIn == state);
	}

	private void switchState(RodState newState) {
		state = newState;
		animationSequence.clear();
		if (newState == RodState.CastBack) {
			ValueEasingAnimation animation = new ValueEasingAnimation(500, angle, -140f, Easing.QUAD_IN_OUT);
			animation.setListener(new ValueEasingAnimation.Listener() {
				public void onEvent(float value) {
					angle = value % 360f;
				}
			});
			animationSequence.add(animation);
			animationSequence.setActive(true);
		} else if (newState == RodState.CastForward) {
			ValueEasingAnimation animation = new ValueEasingAnimation(400, angle, -10f, Easing.QUAD_IN_OUT);
			animation.setListener(new ValueEasingAnimation.Listener() {
				public void onEvent(float value) {
					angle = value % 360f;
				}
			});
			animationSequence.add(animation);
			animationSequence.setActive(true);
		}
	}

}
